import { FormInstance } from 'antd';
import { FormScheme } from '../interface';
import { ObjectOperation } from './object.property';
import { BehaviorSubject } from 'rxjs';

export class FormModel extends ObjectOperation {
  $FormProps: BehaviorSubject<FormScheme>;
  formProps: FormScheme;
  required: string[];
  form: FormInstance;
  name: string;
  initialValues: any;

  constructor(props: FormScheme) {
    const { required, properties, ...formProps } = props;
    const name = formProps.name;
    const namePath = name ? [name] : [];
    super({ type: 'object' }, namePath);
    this.name = name;
    this.required = required;
    this.form = formProps.form;
    this.root = this;
    this.$FormProps = new BehaviorSubject<FormScheme>(formProps);
    this.$FormProps.subscribe((res) => {
      this.formProps = res;
    });

    this.createProperties(properties, namePath, this);
    this.visibleFn();
  }

  setFormProps(props: any = {}) {
    this.$FormProps.next({ ...this.formProps, ...props });
  }

  getFormValues() {
    return this.form.getFieldsValue();
  }

  getFormValidateFields() {
    return this.form.validateFields();
  }

  visibleFn() {
    this.properties.forEach((item) => {
      const { oneOf, allOf, watchProps, watchItemProps } = item;
      if (oneOf) {
        const conditions: boolean[] = Array.from({
          length: Object.keys(oneOf).length,
        });
        Object.entries(oneOf).forEach(([path, fn], index) => {
          const property = this.getProperty(path);
          property?.$valueChange.subscribe((value) => {
            fn(value).then((res) => {
              conditions[index] = res;
              item.setVisible(conditions.some((item) => !!item));
            });
          });
        });
      } else if (allOf) {
        const conditions: boolean[] = Array.from({
          length: Object.keys(allOf).length,
        });
        Object.entries(allOf).forEach(([path, fn], index) => {
          const property = this.getProperty(path);
          property?.$valueChange.subscribe((value) => {
            fn(value).then((res) => {
              conditions[index] = res;
              item.setVisible(conditions.every((item) => !!item));
            });
          });
        });
      }
      if (watchProps) {
        Object.entries(watchProps).forEach(([path, fn], index) => {
          const property = this.getProperty(path);
          property?.$valueChange.subscribe((value) => {
            fn(value).then((res) => {
              item.updateProps(res);
            });
          });
        });
      }
      if (watchItemProps) {
        Object.entries(watchItemProps).forEach(([path, fn], index) => {
          const property = this.getProperty(path);
          property?.$valueChange.subscribe((value) => {
            fn(value).then((res) => {
              item.updateItemProps(res);
            });
          });
        });
      }
    });
  }
}
